#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sysinfo.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <netinet/ether.h>

#include "common.h"
#include "log4cplus.h"

// JH的MAC地址前缀列表
const char *mac_prefixes_jh[] = {
    "8c:1c:da",
    NULL
};

// TYC的MAC地址前缀列表
const char *mac_prefixes_tyc[] = {
    "00:e0:00",
    "d4:25:cc",
    "22:00",
    "d0:9f:d9",
    "00:11:2d",
    NULL
};

static int lockFile(int fd)
{
    struct flock fl;

    fl.l_type = F_WRLCK;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;

    return (fcntl(fd, F_SETLK, &fl)); // F_SETLK在指定的字节范围获取锁
}

bool daemonInit()
{
    pid_t pid;
    if ((pid = fork()) < 0) {
        return (-1);
    } else if (pid != 0) {
        /*parent*/
        exit(0);
    }
    setsid();
    chdir(WORKSPACE_PATH);
    umask(0);
    return true;
}

int alreadyRunning()
{
    int fd;
    char buf[16];

    fd = open(PID_FIlE, O_RDWR | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
    if (fd < 0) {
        return 1;
    }

    if (lockFile(fd) < 0) {
        if (errno == EACCES || errno == EAGAIN) {
            close(fd);
        }
        return 1;
    }

    ftruncate(fd, 0);
    sprintf(buf, "%ld", (long)getpid());
    write(fd, buf, strlen(buf) + 1);

    return 0;
}

HARDWARE_TYPE getHardwareType()
{
    int sockfd;
    struct ifreq ifr;
    unsigned char macAddress[6];
    char macStr[18];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        log_warn_fmt("open socket failure");
        return UNKNOWN;
    }

    strcpy(ifr.ifr_name, INTERFACE_NAME);
    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
        log_warn_fmt("get mac address failure");
        close(sockfd);
        return UNKNOWN;
    }
    close(sockfd);

    memcpy(macAddress, ifr.ifr_hwaddr.sa_data, 6);
    sprintf(macStr, "%02x:%02x:%02x:%02x:%02x:%02x",
            macAddress[0], macAddress[1], macAddress[2],
            macAddress[3], macAddress[4], macAddress[5]);

    log_info_fmt("%s mac address [%s]", INTERFACE_NAME, macStr);

    for (int i = 0; mac_prefixes_jh[i] != NULL; i++) {
        if (strncmp((const char*)macStr, mac_prefixes_jh[i], 
                    strlen(mac_prefixes_jh[i])) == 0) {
            log_info_fmt("current hardware is jh");
            return HARDWARE_JH;
        }
    }

    for (int i = 0; mac_prefixes_tyc[i] != NULL; i++) {
        if (strncmp((const char*)macStr, mac_prefixes_tyc[i], 
                    strlen(mac_prefixes_tyc[i])) == 0) {
            log_info_fmt("current hardware is tyc");
            return HARDWARE_TYC;
        }
    }

    return UNKNOWN;
}

long getSystemUptime()
{
    struct sysinfo info;

    if (sysinfo(&info)) {
        fprintf(stderr, "Get sysinfo failure, errno:%u, reason:%s",
                errno, strerror(errno));
        return -1;
    }
    return info.uptime;
}